#ifndef THINK_THINK_CONSOLE_OUTPUT_DESCRIPTOR_H
#define THINK_THINK_CONSOLE_OUTPUT_DESCRIPTOR_H

static char* think_console_output_descriptor =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: yunwuxin <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\console\\output;\n"
	"\n"
	"use think\\Console;\n"
	"use think\\console\\Command;\n"
	"use think\\console\\input\\Argument as InputArgument;\n"
	"use think\\console\\input\\Definition as InputDefinition;\n"
	"use think\\console\\input\\Option as InputOption;\n"
	"use think\\console\\Output;\n"
	"use think\\console\\output\\descriptor\\Console as ConsoleDescription;\n"
	"\n"
	"class Descriptor\n"
	"{\n"
	"\n"
	"    /**\n"
	"     * @var Output\n"
	"     */\n"
	"    protected $output;\n"
	"\n"
	"    /**\n"
	"     * {@inheritdoc}\n"
	"     */\n"
	"    public function describe(Output $output, $object, array $options = [])\n"
	"    {\n"
	"        $this->output = $output;\n"
	"\n"
	"        switch (true) {\n"
	"            case $object instanceof InputArgument:\n"
	"                $this->describeInputArgument($object, $options);\n"
	"                break;\n"
	"            case $object instanceof InputOption:\n"
	"                $this->describeInputOption($object, $options);\n"
	"                break;\n"
	"            case $object instanceof InputDefinition:\n"
	"                $this->describeInputDefinition($object, $options);\n"
	"                break;\n"
	"            case $object instanceof Command:\n"
	"                $this->describeCommand($object, $options);\n"
	"                break;\n"
	"            case $object instanceof Console:\n"
	"                $this->describeConsole($object, $options);\n"
	"                break;\n"
	"            default:\n"
	"                throw new \\InvalidArgumentException(sprintf(\'Object of type \"%s\" is not describable.\', get_class($object)));\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 输出内容\n"
	"     * @param string $content\n"
	"     * @param bool   $decorated\n"
	"     */\n"
	"    protected function write($content, $decorated = false)\n"
	"    {\n"
	"        $this->output->write($content, false, $decorated ? Output::OUTPUT_NORMAL : Output::OUTPUT_RAW);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 描述参数\n"
	"     * @param InputArgument $argument\n"
	"     * @param array         $options\n"
	"     * @return void\n"
	"     */\n"
	"    protected function describeInputArgument(InputArgument $argument, array $options = [])\n"
	"    {\n"
	"        if (null !== $argument->getDefault()\n"
	"            && (!is_array($argument->getDefault())\n"
	"                || count($argument->getDefault()))\n"
	"        ) {\n"
	"            $default = sprintf(\'<comment> [default: %s]</comment>\', $this->formatDefaultValue($argument->getDefault()));\n"
	"        } else {\n"
	"            $default = \'\';\n"
	"        }\n"
	"\n"
	"        $totalWidth   = isset($options[\'total_width\']) ? $options[\'total_width\'] : strlen($argument->getName());\n"
	"        $spacingWidth = $totalWidth - strlen($argument->getName()) + 2;\n"
	"\n"
	"        $this->writeText(sprintf(\"  <info>%s</info>%s%s%s\", $argument->getName(), str_repeat(\' \', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces\n"
	"            preg_replace(\'/\\s*\\R\\s*/\', PHP_EOL . str_repeat(\' \', $totalWidth + 17), $argument->getDescription()), $default), $options);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 描述选项\n"
	"     * @param InputOption $option\n"
	"     * @param array       $options\n"
	"     * @return void\n"
	"     */\n"
	"    protected function describeInputOption(InputOption $option, array $options = [])\n"
	"    {\n"
	"        if ($option->acceptValue() && null !== $option->getDefault()\n"
	"            && (!is_array($option->getDefault())\n"
	"                || count($option->getDefault()))\n"
	"        ) {\n"
	"            $default = sprintf(\'<comment> [default: %s]</comment>\', $this->formatDefaultValue($option->getDefault()));\n"
	"        } else {\n"
	"            $default = \'\';\n"
	"        }\n"
	"\n"
	"        $value = \'\';\n"
	"        if ($option->acceptValue()) {\n"
	"            $value = \'=\' . strtoupper($option->getName());\n"
	"\n"
	"            if ($option->isValueOptional()) {\n"
	"                $value = \'[\' . $value . \']\';\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $totalWidth = isset($options[\'total_width\']) ? $options[\'total_width\'] : $this->calculateTotalWidthForOptions([$option]);\n"
	"        $synopsis   = sprintf(\'%s%s\', $option->getShortcut() ? sprintf(\'-%s, \', $option->getShortcut()) : \'    \', sprintf(\'--%s%s\', $option->getName(), $value));\n"
	"\n"
	"        $spacingWidth = $totalWidth - strlen($synopsis) + 2;\n"
	"\n"
	"        $this->writeText(sprintf(\"  <info>%s</info>%s%s%s%s\", $synopsis, str_repeat(\' \', $spacingWidth), // + 17 = 2 spaces + <info> + </info> + 2 spaces\n"
	"            preg_replace(\'/\\s*\\R\\s*/\', \"\\n\" . str_repeat(\' \', $totalWidth + 17), $option->getDescription()), $default, $option->isArray() ? \'<comment> (multiple values allowed)</comment>\' : \'\'), $options);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 描述输入\n"
	"     * @param InputDefinition $definition\n"
	"     * @param array           $options\n"
	"     * @return void\n"
	"     */\n"
	"    protected function describeInputDefinition(InputDefinition $definition, array $options = [])\n"
	"    {\n"
	"        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());\n"
	"        foreach ($definition->getArguments() as $argument) {\n"
	"            $totalWidth = max($totalWidth, strlen($argument->getName()));\n"
	"        }\n"
	"\n"
	"        if ($definition->getArguments()) {\n"
	"            $this->writeText(\'<comment>Arguments:</comment>\', $options);\n"
	"            $this->writeText(\"\\n\");\n"
	"            foreach ($definition->getArguments() as $argument) {\n"
	"                $this->describeInputArgument($argument, array_merge($options, [\'total_width\' => $totalWidth]));\n"
	"                $this->writeText(\"\\n\");\n"
	"            }\n"
	"        }\n"
	"\n"
	"        if ($definition->getArguments() && $definition->getOptions()) {\n"
	"            $this->writeText(\"\\n\");\n"
	"        }\n"
	"\n"
	"        if ($definition->getOptions()) {\n"
	"            $laterOptions = [];\n"
	"\n"
	"            $this->writeText(\'<comment>Options:</comment>\', $options);\n"
	"            foreach ($definition->getOptions() as $option) {\n"
	"                if (strlen($option->getShortcut()) > 1) {\n"
	"                    $laterOptions[] = $option;\n"
	"                    continue;\n"
	"                }\n"
	"                $this->writeText(\"\\n\");\n"
	"                $this->describeInputOption($option, array_merge($options, [\'total_width\' => $totalWidth]));\n"
	"            }\n"
	"            foreach ($laterOptions as $option) {\n"
	"                $this->writeText(\"\\n\");\n"
	"                $this->describeInputOption($option, array_merge($options, [\'total_width\' => $totalWidth]));\n"
	"            }\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 描述指令\n"
	"     * @param Command $command\n"
	"     * @param array   $options\n"
	"     * @return void\n"
	"     */\n"
	"    protected function describeCommand(Command $command, array $options = [])\n"
	"    {\n"
	"        $command->getSynopsis(true);\n"
	"        $command->getSynopsis(false);\n"
	"        $command->mergeConsoleDefinition(false);\n"
	"\n"
	"        $this->writeText(\'<comment>Usage:</comment>\', $options);\n"
	"        foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {\n"
	"            $this->writeText(\"\\n\");\n"
	"            $this->writeText(\'  \' . $usage, $options);\n"
	"        }\n"
	"        $this->writeText(\"\\n\");\n"
	"\n"
	"        $definition = $command->getNativeDefinition();\n"
	"        if ($definition->getOptions() || $definition->getArguments()) {\n"
	"            $this->writeText(\"\\n\");\n"
	"            $this->describeInputDefinition($definition, $options);\n"
	"            $this->writeText(\"\\n\");\n"
	"        }\n"
	"\n"
	"        if ($help = $command->getProcessedHelp()) {\n"
	"            $this->writeText(\"\\n\");\n"
	"            $this->writeText(\'<comment>Help:</comment>\', $options);\n"
	"            $this->writeText(\"\\n\");\n"
	"            $this->writeText(\' \' . str_replace(\"\\n\", \"\\n \", $help), $options);\n"
	"            $this->writeText(\"\\n\");\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 描述控制台\n"
	"     * @param Console $console\n"
	"     * @param array   $options\n"
	"     * @return void\n"
	"     */\n"
	"    protected function describeConsole(Console $console, array $options = [])\n"
	"    {\n"
	"        $describedNamespace = isset($options[\'namespace\']) ? $options[\'namespace\'] : null;\n"
	"        $description        = new ConsoleDescription($console, $describedNamespace);\n"
	"\n"
	"        if (isset($options[\'raw_text\']) && $options[\'raw_text\']) {\n"
	"            $width = $this->getColumnWidth($description->getCommands());\n"
	"\n"
	"            foreach ($description->getCommands() as $command) {\n"
	"                $this->writeText(sprintf(\"%-${width}s %s\", $command->getName(), $command->getDescription()), $options);\n"
	"                $this->writeText(\"\\n\");\n"
	"            }\n"
	"        } else {\n"
	"            if (\'\' != $help = $console->getHelp()) {\n"
	"                $this->writeText(\"$help\\n\\n\", $options);\n"
	"            }\n"
	"\n"
	"            $this->writeText(\"<comment>Usage:</comment>\\n\", $options);\n"
	"            $this->writeText(\"  command [options] [arguments]\\n\\n\", $options);\n"
	"\n"
	"            $this->describeInputDefinition(new InputDefinition($console->getDefinition()->getOptions()), $options);\n"
	"\n"
	"            $this->writeText(\"\\n\");\n"
	"            $this->writeText(\"\\n\");\n"
	"\n"
	"            $width = $this->getColumnWidth($description->getCommands());\n"
	"\n"
	"            if ($describedNamespace) {\n"
	"                $this->writeText(sprintf(\'<comment>Available commands for the \"%s\" namespace:</comment>\', $describedNamespace), $options);\n"
	"            } else {\n"
	"                $this->writeText(\'<comment>Available commands:</comment>\', $options);\n"
	"            }\n"
	"\n"
	"            // add commands by namespace\n"
	"            foreach ($description->getNamespaces() as $namespace) {\n"
	"                if (!$describedNamespace && ConsoleDescription::GLOBAL_NAMESPACE !== $namespace[\'id\']) {\n"
	"                    $this->writeText(\"\\n\");\n"
	"                    $this->writeText(\' <comment>\' . $namespace[\'id\'] . \'</comment>\', $options);\n"
	"                }\n"
	"\n"
	"                foreach ($namespace[\'commands\'] as $name) {\n"
	"                    $this->writeText(\"\\n\");\n"
	"                    $spacingWidth = $width - strlen($name);\n"
	"                    $this->writeText(sprintf(\"  <info>%s</info>%s%s\", $name, str_repeat(\' \', $spacingWidth), $description->getCommand($name)\n"
	"                            ->getDescription()), $options);\n"
	"                }\n"
	"            }\n"
	"\n"
	"            $this->writeText(\"\\n\");\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * {@inheritdoc}\n"
	"     */\n"
	"    private function writeText($content, array $options = [])\n"
	"    {\n"
	"        $this->write(isset($options[\'raw_text\'])\n"
	"            && $options[\'raw_text\'] ? strip_tags($content) : $content, isset($options[\'raw_output\']) ? !$options[\'raw_output\'] : true);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 格式化\n"
	"     * @param mixed $default\n"
	"     * @return string\n"
	"     */\n"
	"    private function formatDefaultValue($default)\n"
	"    {\n"
	"        return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @param Command[] $commands\n"
	"     * @return int\n"
	"     */\n"
	"    private function getColumnWidth(array $commands)\n"
	"    {\n"
	"        $width = 0;\n"
	"        foreach ($commands as $command) {\n"
	"            $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;\n"
	"        }\n"
	"\n"
	"        return $width + 2;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @param InputOption[] $options\n"
	"     * @return int\n"
	"     */\n"
	"    private function calculateTotalWidthForOptions($options)\n"
	"    {\n"
	"        $totalWidth = 0;\n"
	"        foreach ($options as $option) {\n"
	"            $nameLength = 4 + strlen($option->getName()) + 2; // - + shortcut + , + whitespace + name + --\n"
	"\n"
	"            if ($option->acceptValue()) {\n"
	"                $valueLength = 1 + strlen($option->getName()); // = + value\n"
	"                $valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]\n"
	"\n"
	"                $nameLength += $valueLength;\n"
	"            }\n"
	"            $totalWidth = max($totalWidth, $nameLength);\n"
	"        }\n"
	"\n"
	"        return $totalWidth;\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif